package uk.ac.glasgow.demosocs.impl.electionTypes;

import java.io.Serializable;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;

import uk.ac.glasgow.demosocs.Candidate;
import uk.ac.glasgow.demosocs.ElectionResult;
import uk.ac.glasgow.demosocs.Vote;
import uk.ac.glasgow.demosocs.VotingSystem;
import uk.ac.glasgow.demosocs.impl.ElectionResultImpl;
import uk.ac.glasgow.demosocs.impl.OneOfNVoteStub;

/**
 * Handles a simple plurality electoral system.
 */
final class SimplePlurality extends ElectoralSystem implements Serializable {

	private static final long serialVersionUID = 1L;
	private Set<Candidate> candidates;
	private Hashtable<String, Integer> votesCasted = new Hashtable<String, Integer>(); // CandidateGUID, number votes
	private Hashtable<String, String> votedFor = new Hashtable<String, String>(); // userID, CandidateID

	public SimplePlurality(Set<Candidate> candidates) {
		this.candidates = candidates;
	}

	@Override
	public void vote(Vote v) {
		OneOfNVoteStub oneOfNVote = ((OneOfNVoteStub) v);
		String candidateId = oneOfNVote.getCandidateGUID();
		String userId = oneOfNVote.getVotedBy();
		
		if (votesCasted.isEmpty())
			initialiseVotesCasted();

		String prevCandidate;
		int votes;

		// 1. user has voted before
		if (votedFor.containsKey(userId)) {
			if (votedFor.get(userId).equals(candidateId)) { // user is trying to
															// vote for the same
															// candidate, ignore
				return;
			} else { // user is trying to vote for a new candidate
				prevCandidate = votedFor.get(userId); // get the candidate that
														// the user voted for
														// previously
				votes = votesCasted.get(prevCandidate);
				votesCasted.put(prevCandidate, votes -= 1); // decrement the
															// number of votes
															// for that previous
															// candidate
			}
		}

	}

	@Override
	public ElectionResult getElectionResult() {
		Iterator i = candidates.iterator();

		if (!i.hasNext())
			return null;

		Candidate winner = (Candidate) i.next();
		Candidate current;

		while (i.hasNext()) {
			current = ((Candidate) i.next());
			if (votesCasted.get(current.getGUID()) > votesCasted.get(winner.getGUID()))
				winner = current;
		}
		return new ElectionResultImpl(winner);
	}

	/**
	 * Returns the type of election "Simple Plurality".
	 */
	public static String getFactoryName() {
		return "Simple_Plurality";
	}

	@Override
	public String getName() {
		return getFactoryName();
	}

	@Override
	public String toString() {
		return "Simple Plurality Factory";
	}

	private void initialiseVotesCasted() {
		for (Candidate c : candidates)
			votesCasted.put(c.getGUID(), 0);
	}



}
